﻿using System.Linq;

namespace SpaceshipDuel
{
    using System.Collections.Generic;
    using System.IO;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using Microsoft.Xna.Framework.Content;

    class SoundProviderOgg
    {
        #region Private fields

        static OggSong sfxMusicTitle;
        static OggSong sfxMusicIngame;
        static OggSong sfxLaserPlayer1;
        static OggSong sfxLaserPlayer2;
        static OggSong sfxLaserEnemy;
        static OggSong sfxPlayershipHit;
        static OggSong sfxObjectHit;
        static OggSong sfxPlayershipExplosion;
        static OggSong sfxPlayershipTeleport;
        static OggSong sfxUpgradeCollected;
        static OggSong sfxEnemyExplosion;

        static SoundEffectInstance siMusicTitle;
        static SoundEffectInstance siMusicIngame;
        static List<SoundEffectInstance> siLaserPlayer1;
        static List<SoundEffectInstance> siLaserPlayer2;
        static List<SoundEffectInstance> siLaserEnemy;
        static List<SoundEffectInstance> siPlayershipHit;
        static List<SoundEffectInstance> siObjectHit;
        static List<SoundEffectInstance> siPlayershipExplosion;
        static List<SoundEffectInstance> siPlayershipTeleport;
        static List<SoundEffectInstance> siUpgradeCollected;
        static List<SoundEffectInstance> siEnemyExplosion;

        #endregion Private fields

        #region Public properties

        public static ContentManager Content { get; set; }

        public static SoundEffectInstance SfxMusicTitle { get { return siMusicTitle; } }

        public static SoundEffectInstance SfxMusicIngame { get { return siMusicIngame; } }

        public static SoundEffectInstance SfxLaserPlayer1
        {
            get
            {
                for (int i = 0; i < siLaserPlayer1.Count; i++)
                    if (siLaserPlayer1[i].State != SoundState.Playing)
                        return siLaserPlayer1[i];
                return CreateNewSoundInstance(ref siLaserPlayer1, sfxLaserPlayer1.Effect);
            }
        }

        public static SoundEffectInstance SfxLaserPlayer2
        {
            get
            {
                for (int i = 0; i < siLaserPlayer2.Count; i++)
                    if (siLaserPlayer2[i].State != SoundState.Playing)
                        return siLaserPlayer2[i];
                return CreateNewSoundInstance(ref siLaserPlayer2, sfxLaserPlayer2.Effect);
            }
        }

        public static SoundEffectInstance SfxLaserEnemy
        {
            get
            {
                for (int i = 0; i < siLaserEnemy.Count; i++)
                    if (siLaserEnemy[i].State != SoundState.Playing)
                        return siLaserEnemy[i];
                return CreateNewSoundInstance(ref siLaserEnemy, sfxLaserEnemy.Effect);
            }
        }

        public static SoundEffectInstance SfxPlayershipHit
        {
            get
            {
                for (int i = 0; i < siPlayershipHit.Count; i++)
                    if (siPlayershipHit[i].State != SoundState.Playing)
                        return siPlayershipHit[i];
                return CreateNewSoundInstance(ref siPlayershipHit, sfxPlayershipHit.Effect);
            }
        }

        public static SoundEffectInstance SfxObjectHit
        {
            get
            {
                for (int i = 0; i < siObjectHit.Count; i++)
                    if (siObjectHit[i].State != SoundState.Playing)
                        return siObjectHit[i];
                return CreateNewSoundInstance(ref siObjectHit, sfxObjectHit.Effect);
            }
        }

        public static SoundEffectInstance SfxPlayershipExplosion
        {
            get
            {
                for (int i = 0; i < siPlayershipExplosion.Count; i++)
                    if (siPlayershipExplosion[i].State != SoundState.Playing)
                        return siPlayershipExplosion[i];
                return CreateNewSoundInstance(ref siPlayershipExplosion, sfxPlayershipExplosion.Effect);
            }
        }

        public static SoundEffectInstance SfxPlayershipTeleport
        {
            get
            {
                for (int i = 0; i < siPlayershipTeleport.Count; i++)
                    if (siPlayershipTeleport[i].State != SoundState.Playing)
                        return siPlayershipTeleport[i];
                return CreateNewSoundInstance(ref siPlayershipTeleport, sfxPlayershipTeleport.Effect);
            }
        }

        public static SoundEffectInstance SfxUpgradeCollected
        {
            get
            {
                for (int i = 0; i < siUpgradeCollected.Count; i++)
                    if (siUpgradeCollected[i].State != SoundState.Playing)
                        return siUpgradeCollected[i];
                return CreateNewSoundInstance(ref siUpgradeCollected, sfxUpgradeCollected.Effect);
            }
        }

        public static SoundEffectInstance SfxEnemyExplosion
        {
            get
            {
                for (int i = 0; i < siEnemyExplosion.Count; i++)
                    if (siEnemyExplosion[i].State != SoundState.Playing)
                        return siEnemyExplosion[i];
                return CreateNewSoundInstance(ref siEnemyExplosion, sfxEnemyExplosion.Effect);
            }
        }

        #endregion Public properties

        #region Public methods

        /// <summary>
        /// Initialisierung aller Daten
        /// </summary>
        public static void InitializeData()
        {
            LoadSounds();
            CreateSoundInstances();
        }

        public static void OnExit()
        {
            siMusicTitle.Stop();
            siMusicIngame.Stop();

            foreach (SoundEffectInstance si in siLaserPlayer1)
                si.Stop();

            foreach (SoundEffectInstance si in siLaserPlayer2)
                si.Stop();

            foreach (SoundEffectInstance si in siLaserEnemy)
                si.Stop();

            foreach (SoundEffectInstance si in siPlayershipHit)
                si.Stop();

            foreach (SoundEffectInstance si in siObjectHit)
                si.Stop();

            foreach (SoundEffectInstance si in siPlayershipExplosion)
                si.Stop();

            foreach (SoundEffectInstance si in siPlayershipTeleport)
                si.Stop();

            foreach (SoundEffectInstance si in siUpgradeCollected)
                si.Stop();

            foreach (SoundEffectInstance si in siEnemyExplosion)
                si.Stop();

            siLaserPlayer1.Clear();
            siLaserPlayer2.Clear();
            siLaserEnemy.Clear();
            siPlayershipHit.Clear();
            siObjectHit.Clear();
            siPlayershipExplosion.Clear();
            siPlayershipTeleport.Clear();
            siUpgradeCollected.Clear();
        }

        #endregion Public methods

        #region Private methods

        /// <summary>
        /// Alle Soundeffekte uas Ogg-Dateien laden
        /// </summary>
        private static void LoadSounds()
        {
            sfxMusicTitle = new OggSong(@".\Content\Sounds\172561__djgriffin__video-game-7.ogg");
            sfxMusicIngame = new OggSong(@".\Content\Sounds\Electronic_Senses_-_Blue_Plexiglasss.ogg");
            sfxLaserPlayer1 = new OggSong(@".\Content\Sounds\laser_shoot_player1.ogg");
            sfxLaserPlayer2 = new OggSong(@".\Content\Sounds\laser_shoot_player2.ogg");
            sfxLaserEnemy = new OggSong(@".\Content\Sounds\laser_shoot_enemy.ogg");
            sfxPlayershipHit = new OggSong(@".\Content\Sounds\hit2.ogg");
            sfxObjectHit = new OggSong(@".\Content\Sounds\hit.ogg");
            sfxPlayershipExplosion = new OggSong(@".\Content\Sounds\explosion.ogg");
            sfxPlayershipTeleport = new OggSong(@".\Content\Sounds\teleport.ogg");
            sfxUpgradeCollected = new OggSong(@".\Content\Sounds\pickup_upgrade.ogg");
            sfxEnemyExplosion = new OggSong(@".\Content\Sounds\explosion2.ogg");
        }

        /// <summary>
        /// Erzeuge Instanzen für alle Soundeffekte
        /// für alle Soundeffekte, die eventuell mehrfach parallel abgespielt werden müssen,
        /// wird eine List<> mit Instanzen angelegt (initial 1 Instanz) und automatisch
        /// über die Get-Methode vergrößert, wenn mehrere Instanzen benötigt werden
        /// </summary>
        private static void CreateSoundInstances()
        {
            siMusicTitle = sfxMusicTitle.Effect.CreateInstance();
            siMusicTitle.Volume = ConfigDataHelper.MusicVolume;
            siMusicTitle.IsLooped = true;

            siMusicIngame = sfxMusicIngame.Effect.CreateInstance();
            siMusicIngame.Volume = ConfigDataHelper.MusicVolume;
            siMusicIngame.IsLooped = true;

            siLaserPlayer1 = new List<SoundEffectInstance>();
            CreateNewSoundInstance(ref siLaserPlayer1, sfxLaserPlayer1.Effect);

            siLaserPlayer2 = new List<SoundEffectInstance>();
            CreateNewSoundInstance(ref siLaserPlayer2, sfxLaserPlayer2.Effect);

            siLaserEnemy = new List<SoundEffectInstance>();
            CreateNewSoundInstance(ref siLaserEnemy, sfxLaserEnemy.Effect);

            siPlayershipHit = new List<SoundEffectInstance>();
            CreateNewSoundInstance(ref siPlayershipHit, sfxPlayershipHit.Effect);

            siObjectHit = new List<SoundEffectInstance>();
            CreateNewSoundInstance(ref siObjectHit, sfxObjectHit.Effect);

            siPlayershipExplosion = new List<SoundEffectInstance>();
            CreateNewSoundInstance(ref siPlayershipExplosion, sfxPlayershipExplosion.Effect);

            siPlayershipTeleport = new List<SoundEffectInstance>();
            CreateNewSoundInstance(ref siPlayershipTeleport, sfxPlayershipTeleport.Effect);

            siUpgradeCollected = new List<SoundEffectInstance>();
            CreateNewSoundInstance(ref siUpgradeCollected, sfxUpgradeCollected.Effect);

            siEnemyExplosion = new List<SoundEffectInstance>();
            CreateNewSoundInstance(ref siEnemyExplosion, sfxEnemyExplosion.Effect);
        }

        /// <summary>
        /// Einen neue Soundeffekt-Instanz anlegen
        /// </summary>
        /// <param name="siList">Liste, der die neue Instanz hinzugefügt werden soll</param>
        /// <param name="sfx">Soundeffekt, der instanziiert werden soll</param>
        /// <returns>neue Soundeffekt-Instanz</returns>
        private static SoundEffectInstance CreateNewSoundInstance(ref List<SoundEffectInstance> siList, SoundEffect sfx)
        {
            SoundEffectInstance newSiInstance;
            newSiInstance = sfx.CreateInstance();
            newSiInstance.Volume = ConfigDataHelper.SfxVolume;
            newSiInstance.IsLooped = false;
            siList.Add(newSiInstance);
            return newSiInstance;
        }

        #endregion Private methods
    }
}
